/*
 * Accordion 1.5 - jQuery menu widget
 *
 * Copyright (c) 2007 Jörn Zaefferer, Frank Marcia
 *
 * http://bassistance.de/jquery-plugins/jquery-plugin-accordion/
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.accordion.js 2951 2007-08-28 07:21:13Z joern.zaefferer $
 *
 */

(function($) {

$.ui = $.ui || {};

$.ui.accordion = {};
$.extend($.ui.accordion, {
    defaults: {
        selectedClass: "selected",
        alwaysOpen: true,
        animated: 'slide',
        event: "click",
        header: "a"
    },
    animations: {
        slide: function(settings, additions) {
            settings = $.extend({
                easing: "swing",
                duration: 300
            }, settings, additions);
            if ( !settings.toHide.size() ) {
                settings.toShow.animate({height: "show"}, {
                    duration: settings.duration,
                    easing: settings.easing,
                    complete: settings.finished
                });
                return;
            }
            var hideHeight = settings.toHide.height(),
                showHeight = settings.toShow.height(),
                difference = showHeight / hideHeight;
            settings.toShow.css({ height: 0, overflow: 'hidden' }).show();
            settings.toHide.filter(":hidden").each(settings.finished).end().filter(":visible").animate({height:"hide"},{
                step: function(n){
                    settings.toShow.height(Math.ceil( (hideHeight - (n)) * difference ));
                },
                duration: settings.duration,
                easing: settings.easing,
                complete: settings.finished
            });
        },
        bounceslide: function(settings) {
            this.slide(settings, {
                easing: settings.down ? "bounceout" : "swing",
                duration: settings.down ? 1000 : 200
            });
        },
        easeslide: function(settings) {
            this.slide(settings, {
                easing: "easeinout",
                duration: 700
            })
        }
    }
});

$.fn.extend({
    nextUntil: function(expr) {
        var match = [];

        // We need to figure out which elements to push onto the array
        this.each(function(){
            // Traverse through the sibling nodes
            for( var i = this.nextSibling; i; i = i.nextSibling ) {
                // Make sure that we're only dealing with elements
                if ( i.nodeType != 1 ) continue;

                // If we find a match then we need to stop
                if ( $.filter( expr, [i] ).r.length ) break;

                // Otherwise, add it on to the stack
                match.push( i );
            }
        });

        return this.pushStack( match );
    },
    // the plugin method itself
    accordion: function(settings) {
        if ( !this.length )
            return this;

        // setup configuration
        settings = $.extend({}, $.ui.accordion.defaults, settings);

        if ( settings.navigation ) {
            var current = this.find("a").filter(function() { return this.href == location.href; });
            if ( current.length ) {
                if ( current.filter(settings.header).length ) {
                    settings.active = current;
                } else {
                    settings.active = current.parent().parent().prev();
                    current.addClass("current");
                }
            }
        }

        // calculate active if not specified, using the first header
        var container = this,
            headers = container.find(settings.header),
            active = findActive(settings.active),
            running = 0;

        if ( settings.fillSpace ) {
            var maxHeight = this.parent().height();
            headers.each(function() {
                maxHeight -= $(this).outerHeight();
            });
            var maxPadding = 0;
            headers.nextUntil(settings.header).each(function() {
                maxPadding = Math.max(maxPadding, $(this).innerHeight() - $(this).height());
            }).height(maxHeight - maxPadding);
        } else if ( settings.autoheight ) {
            var maxHeight = 0;
            headers.nextUntil(settings.header).each(function() {
                maxHeight = Math.max(maxHeight, $(this).height());
            }).height(maxHeight);
        }

        headers
            .not(active || "")
            .nextUntil(settings.header)
            .hide();
        active.parent().andSelf().addClass(settings.selectedClass);


        function findActive(selector) {
            return selector != undefined
                ? typeof selector == "number"
                    ? headers.filter(":eq(" + selector + ")")
                    : headers.not(headers.not(selector))
                : selector === false
                    ? $("<div>")
                    : headers.filter(":eq(0)");
        };

        function toggle(toShow, toHide, data, clickedActive, down) {
            var finished = function(cancel) {
                running = cancel ? 0 : --running;
                if ( running )
                    return;
                // trigger custom change event
                container.trigger("change", data);
            };

            // count elements to animate
            running = toHide.size() == 0 ? toShow.size() : toHide.size();

            if ( settings.animated ) {
                if ( !settings.alwaysOpen && clickedActive ) {
                    toShow.slideToggle(settings.animated);
                    finished(true);
                } else {
                    $.ui.accordion.animations[settings.animated]({
                        toShow: toShow,
                        toHide: toHide,
                        finished: finished,
                        down: down
                    });
                }
            } else {
                if ( !settings.alwaysOpen && clickedActive ) {
                    toShow.toggle();
                } else {
                    toHide.hide();
                    toShow.show();
                }
                finished(true);
            }
        };

        function clickHandler(event) {
            // called only when using activate(false) to close all parts programmatically
            if ( !event.target && !settings.alwaysOpen ) {
                active.toggleClass(settings.selectedClass);
                var toHide = active.nextUntil(settings.header);
                var toShow = active = $([]);
                toggle( toShow, toHide );
                return;
            }
            // get the click target
            var clicked = $(event.target);

            // due to the event delegation model, we have to check if one
            // of the parent elements is our actual header, and find that
            if ( clicked.parents(settings.header).length )
                while ( !clicked.is(settings.header) )
                    clicked = clicked.parent();

            var clickedActive = clicked[0] == active[0];

            // if animations are still active, or the active header is the target, ignore click
            if(running || (settings.alwaysOpen && clickedActive) || !clicked.is(settings.header))
                return;

            // switch classes
            active.parent().andSelf().toggleClass(settings.selectedClass);
            if ( !clickedActive ) {
                clicked.parent().andSelf().addClass(settings.selectedClass);
            }

            // find elements to show and hide
            var toShow = clicked.nextUntil(settings.header),
                toHide = active.nextUntil(settings.header),
                data = [clicked, active, toShow, toHide],
                down = headers.index( active[0] ) > headers.index( clicked[0] );

            active = clickedActive ? $([]) : clicked;
            toggle( toShow, toHide, data, clickedActive, down );

            return !toShow.length;
        };
        function activateHandler(event, index) {
            // IE manages to call activateHandler on normal clicks
            if ( arguments.length == 1 )
                return;
            // call clickHandler with custom event
            clickHandler({
                target: findActive(index)[0]
            });
        };

        return container
            .bind(settings.event, clickHandler)
            .bind("activate", activateHandler);
    },
    activate: function(index) {
        return this.trigger('activate', [index]);
    }
});

})(jQuery);